package com.vuej.core;

import org.apache.commons.io.IOUtils;

import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 基础脚本运行环境，包括
 * 1.java js环境 ScriptEngine
 * 2.global,console,promise,XMLHttpRequest等的Polyfill
 * 3.vue、vuex、vue-ssr basic
 */
public class ScriptEnvironment {

    protected final ScriptEngine engine;

    private static final ScheduledExecutorService defaultPool = Executors.newScheduledThreadPool(20);


    public ScriptEngine getEngine() {
        return engine;
    }

    /**
     * 构造基础脚本运行环境,使用全局默认线程池 Executors.newScheduledThreadPool(20)
     */
    public ScriptEnvironment(){
        this(defaultPool);
    }

    /**
     * 构造基础脚本运行环境，使用自定义线程池
     * @param scheduledExecutorService 线程池，用来实现setTimeOut方法
     */
    public ScriptEnvironment(ScheduledExecutorService scheduledExecutorService) {
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        this.engine = scriptEngineManager.getEngineByName("javascript");
        try{
            this.initEngine(scheduledExecutorService);
            this.initVue();
        }catch (IOException|ScriptException e){
           throw new IllegalStateException("fatal error: cannot init script environment: " + e.getMessage(),e);
        }
    }

    public void evalClassLib(String path) throws IOException, ScriptException {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
        if(inputStream == null){
            throw new FileNotFoundException("resource not found: " + path);
        }
        String script = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

        evalString(script);
    }

    public void evalString(String script) throws ScriptException{
        getEngine().eval(script);
    }


    protected void initEngine(ScheduledExecutorService scheduledExecutorService) throws IOException,ScriptException {
        evalClassLib("lib/nashorn-polyfill/global-polyfill.js");
        evalClassLib("lib/nashorn-polyfill/blob-polyfill.js");
        evalClassLib("lib/nashorn-polyfill/timer-polyfill.js");
        evalClassLib("lib/nashorn-polyfill/xml-http-request-polyfill.js");
        evalClassLib("lib/promise-polyfill.js");
        evalClassLib("lib/jvm-npm.js");

        getEngine().getContext().setAttribute("__NASHORN_POLYFILL_TIMER__",scheduledExecutorService,ScriptContext.ENGINE_SCOPE);
    }

    protected void initVue() throws IOException,ScriptException{
        evalClassLib("lib/vue/vue.js");
        evalClassLib("lib/vue/vuex.js");
        evalClassLib("lib/vue/vue-server-renderer-basic.js");
    }

}
